package com.ukit.weather_xml.weather

import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.json.JSONObject
import java.net.HttpURLConnection
import java.net.URL

interface Codec<T> {
    fun encode(obj: T): String
    fun decode(json: String): T
}

class JsonCodec<T>(private val clazz: Class<T>) : Codec<T> {
    private val gson = Gson()

    override fun encode(obj: T): String {
        return gson.toJson(obj)
    }

    override fun decode(json: String): T {
        return gson.fromJson(json, clazz)
    }
}

class WeatherConnector(private var city: String) {
    private val key = "841d4425f36a45ecb15150614241804"
    private val gson = Gson()
    private val locationCodec = JsonCodec(Location::class.java)
    private val currentCodec = JsonCodec(Current::class.java)
    private val forecastdayCodec = JsonCodec(Forecastday::class.java)
    private val hourCodec = JsonCodec(Hour::class.java)
    private val dayCodec = JsonCodec(Day::class.java)
    private val astroCodec = JsonCodec(Astro::class.java)

    public fun setCity(newCity: String){
        city = newCity
    }

    private suspend fun getWeatherJson(): String {
        return withContext(Dispatchers.IO) {
            var result = ""
            val connection = URL("https://api.weatherapi.com/v1/forecast.json?key=${key}&q=${city}&days=4&aqi=yes&alerts=no").openConnection() as HttpURLConnection
            try {
                connection.connect()
                result = connection.inputStream.use { it.reader().use { reader -> reader.readText() } }
            } finally {
                connection.disconnect()
            }
            result
        }
    }

    suspend fun getWeather(): WeatherDataX {
        val jsonData = getWeatherJson()
        val jsonObject = JSONObject(jsonData)

        val locationJson = jsonObject.getJSONObject("location").toString()
        val location = locationCodec.decode(locationJson)

        val currentJson = jsonObject.getJSONObject("current").toString()
        val current = currentCodec.decode(currentJson)

        val forecastdayList = mutableListOf<Forecastday>()
        val forecastObject = jsonObject.getJSONObject("forecast")
        val forecastdayArray = forecastObject.getJSONArray("forecastday")

        for (i in 0 until forecastdayArray.length()) {
            val forecastdayObject = forecastdayArray.getJSONObject(i)
            val astroJson = forecastdayObject.getJSONObject("astro").toString()
            val astro = astroCodec.decode(astroJson)

            val dayJson = forecastdayObject.getJSONObject("day").toString()
            val day = dayCodec.decode(dayJson)

            val hourList = mutableListOf<Hour>()
            val hourArray = forecastdayObject.getJSONArray("hour")
            for (j in 0 until hourArray.length()) {
                val hourJson = hourArray.getJSONObject(j).toString()
                val hour = hourCodec.decode(hourJson)
                hourList.add(hour)
            }

            val forecastday = Forecastday(
                forecastdayObject.getLong("date_epoch"),
                forecastdayObject.getString("date"),
                day,
                astro,
                hourList
            )
            forecastdayList.add(forecastday)
        }

        return WeatherDataX(current, forecastdayList, location)
    }
}
